﻿
namespace Sai.Core
{
    using Sai.Core.Introspection;
    using System.Collections.Generic;
    using System.Text;

    public class SourceCodeTypeNameBuilder
    {
        private TypeNameTag typeNameTag;

        public static SourceCodeTypeNameBuilder Type()
        {
            return new SourceCodeTypeNameBuilder();
        }

        public static SourceCodeTypeNameBuilder Type(TypeName t)
        {
            SourceCodeTypeNameBuilder builder = new SourceCodeTypeNameBuilder();

            builder.Named(t.FullName.ToString());

            return builder;
        }

        public SourceCodeTypeNameBuilder Named(string name)
        {
            this.typeNameTag = new TypeNameTag(name);
            
            return this;
        }

        public SourceCode Build()
        {
            SourceCode code = new SourceCode();

            code.Add(this.typeNameTag);
            
            return code;
        }
    }

    public class SourceCodeFieldBuilder
    {
        private TypeNameTag typeName;
        private IdentifierTag identifier;

        public static SourceCodeFieldBuilder Field()
        {
            return new SourceCodeFieldBuilder();
        }

        public SourceCodeFieldBuilder Named(string name)
        {
            this.identifier = new IdentifierTag(name);
            return this;
        }

        public SourceCodeFieldBuilder WithType(string fieldType)
        {
            this.typeName = new TypeNameTag(fieldType);
            return this;
        }

        public SourceCode Build()
        {
            SourceCode code = new SourceCode();

            code.Add(this.typeName);
            code.Add(this.identifier);

            return code;
        }
    }

    public class SourceCodeMethodBuilder
    {
        private IdentifierTag identifier;
        private TypeNameTag typeName;
        private List<TypeNameTag> argumentList = new List<TypeNameTag>();
        private KeywordTag isAbstract = null;

        public static SourceCodeMethodBuilder Method()
        {
            return new SourceCodeMethodBuilder();
        }

        public SourceCodeMethodBuilder Named(string name)
        {
            this.identifier = new IdentifierTag(name);
            return this;
        }

        public SourceCodeMethodBuilder WithReturnType(string returnType)
        {
            this.typeName = new TypeNameTag(returnType);
            return this;
        }

        public SourceCodeMethodBuilder IsAbstract()
        {
            this.isAbstract = new KeywordTag("abstract");
            return this;
        }

        public SourceCodeMethodBuilder IsAbstract(bool flag)
        {
            this.isAbstract = flag ? new KeywordTag("abstract") : null;
            return this;
        }

        public SourceCodeMethodBuilder WithArg(string argType)
        {
            this.argumentList.Add(new TypeNameTag(argType));

            return this;
        }

        public SourceCode Build()
        {
            SourceCode code = new SourceCode();

            if (this.typeName != null)
            {
                code.Add(this.typeName);
            }

            if (this.isAbstract != null)
            {
                code.Add(this.isAbstract);
            }

            code.Add(this.identifier);

            code.Add(new PunctuationTag("("));

            for (int i = 0; i < this.argumentList.Count; ++i)
            {
                code.Add(this.argumentList[i]);

                if (i < this.argumentList.Count - 1)
                {
                    code.Add(new PunctuationTag(","));
                }
            }

            code.Add(new PunctuationTag(")"));

            return code;
        }
    }

    public class ClassDeclarationSourceCodeBuilder
    {
        private IdentifierTag identifier;

        public static ClassDeclarationSourceCodeBuilder Class()
        {
            return new ClassDeclarationSourceCodeBuilder();
        }

        public static ClassDeclarationSourceCodeBuilder Class(ClassDeclaration cdec)
        {
            ClassDeclarationSourceCodeBuilder builder = new ClassDeclarationSourceCodeBuilder();

            builder.Named(cdec.TypeName.Name);

            return builder;
        }

        public ClassDeclarationSourceCodeBuilder Named(string name)
        {
            this.identifier = new IdentifierTag(name);
            return this;
        }

        public SourceCode Build()
        {
            SourceCode code = new SourceCode();

            code.Add(new KeywordTag("public"));

            //if (this.IsAbstract)
            //{
            //    code.Add(new KeywordTag("abstract"));
            //}

            //if (this.IsSealed)
            //{
            //    code.Add(new KeywordTag("sealed"));
            //}

            //code.Add(new KeywordTag("class"));
            //code.Add(new TypeNameTag(this.TypeName.FullName));

            return code;
        }
    }
}
